﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using PowerPoint = Microsoft.Office.Interop.PowerPoint;
using ThreeByte.ActiveDeck.Content;
using System.Threading;
using ThreeByte.ActiveDeck.Config;
using ThreeByte.ActiveDeck.Controls;
using ThreeByte.ActiveDeck.Service;
using log4net;
using System.Xml.Linq;
using ThreeByte.ActiveDeck.Data.UserResponse;
using System.Reflection;
using System.Windows.Media.Animation;
using ThreeByte.ActiveDeck.AddIn.Controls;
using Microsoft.Office.Tools;

namespace ThreeByte.ActiveDeck
{
    /// <summary>
    /// Interaction logic for WPFControl.xaml
    /// </summary>
    public partial class WPFControl : UserControl
    {
        private static readonly ILog log = LogManager.GetLogger(typeof(WPFControl));

        static WPFControl() {
            Assembly theAssembly = Application.ResourceAssembly;
            //Set the assembly here
            Application.ResourceAssembly = Assembly.GetExecutingAssembly();
            log.DebugFormat("The Assembly: {0}", Application.ResourceAssembly);
        }

        public WPFControl(CoreConfig config) {
            Config = config;
            InitializeComponent();

            UpdateIsTriggerEnabled(false);
            ShowPropertiesCheckBox.DataContext = Config.Environment;
        }

        public CustomTaskPane TaskPane {
            get;
            set;
        }

        public CoreConfig Config { get; private set; }
        public int CurrentSlideId { get; private set; }
        public int CurrentPageId { get; private set; }

        public void LoadConfigForSlide(PowerPoint.SlideRange slideRange) {

            CurrentSlideId = slideRange.SlideID;

            SlideNumberTextBlock.Text = string.Format("Slide Num: {0}", slideRange.SlideNumber);
            SlideNumberTextBlock.ToolTip = string.Format("ID {0}", slideRange.SlideID);

            if (Config.ContainsId(CurrentSlideId)) {
                TriggeriPadCheckBox.IsChecked = true;
                UpdateUIWithConfig(Config[CurrentSlideId]);
            } else {
                TriggeriPadCheckBox.IsChecked = false;
                UpdateUIWithConfig(null);
            }

            //UpdateUserDataControls();
        }



        private void UpdateUIWithConfig(SlideConfig config) {
            if(config == null) {
                CurrentPageId = 0;
                UpdatePagingUI();
                return;
            }
            //Grab the first PageConfig and load it up
            PageConfig firstPage = config.Pages.First();
            CurrentPageId = firstPage.PageId;

            PageConfigurationControl newConfigControl = new PageConfigurationControl(firstPage);
            newConfigControl.PageConfigUpdated += new EventHandler<PageConfigUpdatedEventArgs>(newControl_PageConfigUpdated);

            TranslateRoot.Children.Clear();
            TranslateRoot.Children.Add(newConfigControl);

            UpdatePagingUI();

        }

        private void UpdatePagingUI() {
            //Update the paging controls
            if(CurrentPageId == 0) {
                PageNavigationPanel.Visibility = Visibility.Hidden;
                PageAddPanel.Visibility = Visibility.Hidden;
                return;
            }
            PageNavigationPanel.Visibility = Visibility.Visible;
            PageAddPanel.Visibility = Visibility.Visible;

            SlideConfig currentSlideConfig = Config[CurrentSlideId];
            PageConfig currentPageConfig = currentSlideConfig[CurrentPageId];

            if(currentSlideConfig.PageCount > 1) {
                PageNavigationPanel.Visibility = Visibility.Visible;
                DeletePageButton.Visibility = Visibility.Visible;
            } else if(currentSlideConfig.PageCount == 1) {
                PageNavigationPanel.Visibility = Visibility.Hidden;
                DeletePageButton.Visibility = Visibility.Collapsed;
            } else {
                //This should never happen
                throw new InvalidOperationException("Cannot update the slideconfig with no pages");
            }

            PrevButton.IsEnabled = !(currentSlideConfig.IsFirstPage(currentPageConfig));
            NextButton.IsEnabled = !(currentSlideConfig.IsLastPage(currentPageConfig));
            //Recount to get the index rather than the id
            PageNumberTextBlock.ToolTip = string.Format("ID {0}", CurrentPageId);
            PageNumberTextBlock.Text = string.Format("{0}", currentSlideConfig.IndexOf(currentPageConfig));
        }

        
        private void UpdateIsTriggerEnabled(bool trigger) {
            TranslateRoot.Visibility = (trigger ? Visibility.Visible : Visibility.Collapsed);
            
            if(trigger) {
                if(!(Config.ContainsId(CurrentSlideId))) {
                    Config[CurrentSlideId] = new SlideConfig(CurrentSlideId);
                }
                UpdateUIWithConfig(Config[CurrentSlideId]);
            } else {
                Config.RemoveId(CurrentSlideId);
                UpdateUIWithConfig(null);
            }
        }

        private void TriggeriPadCheckBox_Checked(object sender, RoutedEventArgs e) {
            UpdateIsTriggerEnabled(true);
        }

        private void TriggeriPadCheckBox_Unchecked(object sender, RoutedEventArgs e) {
            UpdateIsTriggerEnabled(false);
        }

        //private void UpdateUserDataControls() {
        //    bool enable = (Config.HasPresentationID && Config.HasPresenterLogin);
        //    RefreshUserResponseButton.IsEnabled = enable;
        //    DeleteUserDataButton.IsEnabled = enable;
        //}

        //private void RefreshUserResponseButton_Click(object sender, RoutedEventArgs e) {
        //    //Update the graphic here
        //    log.Info("Updating the User Data");

        //    int section = CurrentSlideId;
        //    int page = 1; //TODO: Deal with the Page issue
            
        //    try {
        //        XNamespace ns = ServiceConfiguration.NAMESPACE;
        //        WebServiceClient client = new WebServiceClient(Config.PresenterLogin);
        //        XElement userDataNode = client.GetUserData(Config.ID, section, page).Element(ns + "Aggregate");

        //        string type = userDataNode.Attribute("Type").Value;
        //        AggregateUserData userData = null;

        //        //TODO: Consolidate this code
        //        switch(type) {
        //            case "ShortAnswer":
        //                userData = ShortAnswerUserData.ParseXml(userDataNode);
        //                break;
        //            case "MultipleChoice":
        //                userData = MultipleChoiceUserData.ParseXml(userDataNode);
        //                break;
        //            case "Categories":
        //                userData = CategoriesUserData.ParseXml(userDataNode);
        //                break;
        //            default:
        //                throw new ArgumentOutOfRangeException("Type", "Cannot read user data type: " + type);
        //        }
        //        if(userData == null) {
        //            log.Warn("No User data to update");
        //            UserResponsePanel.Visibility = Visibility.Collapsed;
        //        } else {
        //            TotalUserSubmissionTextBlock.Text = string.Format("{0}", userData.TotalResponses);
        //            UserResponsePanel.Visibility = Visibility.Visible;
        //        }

        //    } catch(Exception ex) {
        //        log.Error("Error Retrieving user Data", ex);
        //        UserResponsePanel.Visibility = Visibility.Collapsed;
        //    }

        //}

        private void DeleteUserDataButton_Click(object sender, RoutedEventArgs e) {
            //Delete the user data from the activity

            int section = CurrentSlideId;
            int page = 1; //TODO: Deal with the Page issue

            try {
                WebServiceClient client = new WebServiceClient(Config.PresenterLogin);
                client.ResetUserData(Config.ID, section, page);
            } catch(Exception ex) {
                log.Warn("Problem deleting user data", ex);
                //Tell the user that this didn't work
                MessageBox.Show("The User data could not be deleted");
            }
        }

        private Storyboard sb;

        private void NextButton_Click(object sender, RoutedEventArgs e) {
            PageConfig nextPage = Config[CurrentSlideId].GetPageAfter(Config[CurrentSlideId][CurrentPageId]);
            CurrentPageId = nextPage.PageId; 
            StartAnimation(nextPage, FlowDirection.LeftToRight);
        }

        private void PreviousButton_Click(object sender, RoutedEventArgs e) {
            PageConfig prevPage = Config[CurrentSlideId].GetPageBefore(Config[CurrentSlideId][CurrentPageId]);
            CurrentPageId = prevPage.PageId;
            StartAnimation(prevPage, FlowDirection.RightToLeft);
        }

        private void StartAnimation(PageConfig newPage, FlowDirection direction) {

            //Animate off to the side
            NextButton.IsEnabled = false;
            PrevButton.IsEnabled = false;

            double dir = 1.0;
            if(direction == FlowDirection.RightToLeft) {
                dir = -1.0;
            }

            FrameworkElement el = (FrameworkElement)(TranslateRoot.Children[0]);
            el.RenderTransform = new TranslateTransform();
            DoubleAnimation anim = new DoubleAnimation(0.0, el.ActualWidth * dir * -1.0, new Duration(TimeSpan.FromSeconds(0.4)));
            anim.EasingFunction = new QuadraticEase(){ EasingMode = System.Windows.Media.Animation.EasingMode.EaseInOut };
            //Register this name
            TranslateRoot.RegisterName("CurrentElement", el);

            //Create a new control
            PageConfigurationControl newControl = new PageConfigurationControl(newPage);
            newControl.PageConfigUpdated += new EventHandler<PageConfigUpdatedEventArgs>(newControl_PageConfigUpdated);
            newControl.RenderTransform = new TranslateTransform(el.ActualWidth * dir, 0.0);
            newControl.Name = "NextElement";
            TranslateRoot.RegisterName(newControl.Name, newControl);
            
            //Add it to the grid
            TranslateRoot.Children.Add(newControl);

            //And animate the controls in the opposite direction
            DoubleAnimation anim2 = new DoubleAnimation(el.ActualWidth * dir, 0.0, new Duration(TimeSpan.FromSeconds(0.4)));
            anim2.EasingFunction = anim.EasingFunction;

            sb = new Storyboard();
            sb.Children.Add(anim);
            sb.Children.Add(anim2);
            Storyboard.SetTargetName(anim, "CurrentElement");
            Storyboard.SetTargetName(anim2, "NextElement");
            Storyboard.SetTargetProperty(anim, new PropertyPath("(FrameworkElement.RenderTransform).(TranslateTransform.X)"));
            Storyboard.SetTargetProperty(anim2, new PropertyPath("(FrameworkElement.RenderTransform).(TranslateTransform.X)"));
            sb.Completed += new EventHandler(sb_Completed);

            sb.Begin(TranslateRoot);
        }

        void newControl_PageConfigUpdated(object sender, PageConfigUpdatedEventArgs e) {
            //Replace the current page with the new one
            Config[CurrentSlideId].ReplacePage(e.OldPageConfig, e.NewPageConfig);
            CurrentPageId = e.NewPageConfig.PageId;
        }

        void sb_Completed(object sender, EventArgs e) {
            Console.WriteLine("Storyboard Complete");

            PageConfigurationControl current = (PageConfigurationControl)(TranslateRoot.FindName("CurrentElement"));
            current.PageConfigUpdated -= newControl_PageConfigUpdated;
            TranslateRoot.UnregisterName("CurrentElement");
            TranslateRoot.UnregisterName("NextElement");

            TranslateRoot.Children.Remove(current);
            sb.Remove();

            //At this point there should only be one element left in the translate grid and we should be able to apply the animation again.

            //Reenable animations
            UpdatePagingUI();
        }

        private void DeletePageButton_Click(object sender, RoutedEventArgs e) {
            //Delete this pageconfig
            PageConfig pageToDelete = Config[CurrentSlideId][CurrentPageId];

            if(Config[CurrentSlideId].IsFirstPage(pageToDelete)
                && Config[CurrentSlideId].IsLastPage(pageToDelete)) {
                    throw new InvalidOperationException("Cannot delete the last remaining page in a slide configuration");
            }


            if(Config[CurrentSlideId].IsLastPage(pageToDelete)) {
                //Animate back or forward, if there are other elements
                PageConfig remainingPage = Config[CurrentSlideId].GetPageBefore(pageToDelete);
                CurrentPageId = remainingPage.PageId;
                StartAnimation(remainingPage, FlowDirection.RightToLeft);
                Config[CurrentSlideId].RemovePage(pageToDelete);
            } else {
                PageConfig remainingPage = Config[CurrentSlideId].GetPageAfter(pageToDelete);
                CurrentPageId = remainingPage.PageId;
                StartAnimation(remainingPage, FlowDirection.LeftToRight);
                Config[CurrentSlideId].RemovePage(pageToDelete);
            }

        }

        private void AddPageButton_Click(object sender, RoutedEventArgs e) {
            //Construct a new PageConfig
            PageConfig newPage = PageConfig.NewDefaultPage();

            //Add it to the SlideConfig list
            Config[CurrentSlideId].AddPageAfter(CurrentPageId, newPage);
            CurrentPageId = newPage.PageId;

            //Then animate to it
            StartAnimation(newPage, FlowDirection.LeftToRight);

        }
 
    }

    public class TemplateType
    {
        public string DisplayName { get; set; }
        public Type ConfigType { get; set; }
    }
}
